package com.itlaobing.aop.schema;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;

import java.util.Arrays;
import java.util.logging.Logger;

public class DaoAdvice {

    private Logger logger = Logger.getLogger( this.getClass().getName() );

    /**
     * 这里用该方法用来表示在切点选择的方法执行之前织入的 Advice
     * @param point 表示连接点，通过 AspectJ 提供的支持，可以通过连接点获得方法的相关信息
     */
    public void before1( JoinPoint point ){
        Signature s = point.getSignature() ; // 获取连接点对应的方法签名
        String name = s.getName() ; // 获得方法名称
        logger.info( "[" + name + "]即将执行" );
    }

    public void before2( JoinPoint point ){
        Signature s = point.getSignature() ; // 获取连接点对应的方法签名
        String name = s.getName() ; // 获得方法名称
        logger.info( "[" + name + "]即将执行" );
    }

    /**
     * @param point 表示连接点，对于通过around(环绕)织入的Advice来说，其参数是ProceedingJoinPoint
     *              通过 ProceedingJoinPoint 实例可以让被拦截的方法继续执行，通过 proceed(Object[]) 或 proceed() 实现。
     * @return 被拦截的目标方法返回什么该方法就返回什么。该方法的返回值也会被 after-return 继续处理。
     * @throws Throwable 当被拦截的方法在执行时发生异常时该方法也抛出异常。该方法抛出的异常可以被 after-throw 继续处理
     */
    public Object around1( ProceedingJoinPoint point ) throws Throwable {
        Signature s = point.getSignature();
        String name = s.getName() ;
        logger.info( "开始为[" + name + "]执行计时" );
        long begin = System.nanoTime() ;
        Object[] args = point.getArgs(); // 获得被拦截的方法执行时的参数
        logger.info( "参数:" +  Arrays.toString( args ) );
        Object result = point.proceed( args );
        // Object result = point.proceed(); // 不需要处理参数时可以直接使用该方法
        long end = System.nanoTime();
        logger.info( "["+ name +"]执行用时[" + ( end - begin )+ "ns.]" );
        return result ;
    }

    public Object around2( ProceedingJoinPoint point ) throws Throwable {
        Signature s = point.getSignature();
        String name = s.getName() ;
        logger.info( "开始为[" + name + "]执行计时" );
        long begin = System.nanoTime() ;
        Object result = point.proceed(); // 不需要处理参数时可以直接使用该方法
        long end = System.nanoTime();
        logger.info( "["+ name +"]执行用时[" + ( end - begin )+ "ns.]" );
        return result ;
    }

    /**
     * @param point 表示连接点
     * @param itlaobing 表示方法正常执行后的返回值，
     *                  该参数名称需要与 aop.xml 中 aop:after-returning 元素的 returning 属性值保持一致
     */
    public void afterReturn( JoinPoint point , Object itlaobing ){
        Signature s = point.getSignature();
        String name = s.getName() ;
        logger.info( "[" + name + "]执行后返回了[" + itlaobing + "]");
    }

    /**
     * @param point 表示连接点
     * @param ex 表示方法执行时抛出的异常，
     *           该参数名称需要与 aop.xml 中 aop:after-throwing 元素的 throwing 属性值保持一致
     */
    public void afterThrow( JoinPoint point , Throwable ex ) {
        Signature s = point.getSignature();
        String name = s.getName() ;
        logger.info( "[" + name + "]执行时发生错误[" + ex.toString() + "]");
    }

    public void after1( JoinPoint point ){
        Signature s = point.getSignature() ; // 获取连接点对应的方法签名
        String name = s.getName() ; // 获得方法名称
        logger.info( "[" + name + "]执行结束" );
    }

    public void after2( JoinPoint point ){
        Signature s = point.getSignature() ; // 获取连接点对应的方法签名
        String name = s.getName() ; // 获得方法名称
        logger.info( "[" + name + "]执行结束" );
    }
}
